import { Injectable, Logger, NotFoundException, BadRequestException } from '@nestjs/common';
import { DatabaseService } from './database.service';
import { 
  CreateBSCTokenDto, 
  BuyBSCTokenDto,
  SellBSCTokenDto,
  ContributeBSCTokenDto,
  GraduateBSCTokenDto,
  CancelBSCLaunchDto,
  ClaimRefundDto
} from '../dto/bsc.dto';
import * as fs from 'fs';
import * as path from 'path';
import { ethers } from 'ethers';
import BSCContractHelper, { BSC_CONTRACT_CONFIG } from '../contracts/bsc-contract';

export interface BSCToken {
  id: string;
  launchId: number;
  tokenAddress: string;
  creator: string;
  name: string;
  symbol: string;
  description: string;
  website?: string;
  telegram?: string;
  twitter?: string;
  imageUrl?: string;
  targetAmount: string;
  raisedAmount: string;
  createdAt: number;
  deadline: number;
  launched: boolean;
  cancelled: boolean;
  currentPrice: string;
  tokensSold: string;
  totalSupplyForSale: string;
  priceChange24h?: number | null;
  volume24h?: string;
  marketCap?: string;
  holders?: number;
}

export interface BSCContribution {
  id: string;
  launchId: number;
  contributor: string;
  amount: string;
  tokensReceived: string;
  bnbReceived?: string;
  timestamp: number;
  txHash: string;
  tradeType: 'buy' | 'sell';
}

@Injectable()
export class BSCService {
  private readonly logger = new Logger(BSCService.name);
  private contractHelper: BSCContractHelper;
  private readonly LAUNCHPAD_ADDRESS = BSC_CONTRACT_CONFIG.address;
  
  constructor(private databaseService: DatabaseService) {
    // Initialize BSC contract helper
    this.contractHelper = new BSCContractHelper();
    this.logger.log(`BSC Service initialized with contract: ${this.LAUNCHPAD_ADDRESS}`);
  }

  async getStats() {
    try {
      // Get stats from database
      const result = await this.databaseService.query(`
        SELECT 
          COUNT(*) as totalTokens,
          COALESCE(SUM(CASE WHEN raised_amount IS NOT NULL THEN CAST(raised_amount AS DECIMAL) ELSE 0 END), 0) as totalVolume,
          COUNT(DISTINCT creator) as activeTraders,
          COUNT(CASE WHEN launched = true THEN 1 END) as successfulLaunches,
          COALESCE(AVG(CASE WHEN raised_amount IS NOT NULL THEN CAST(raised_amount AS DECIMAL) ELSE 0 END), 0) as averageRaise
        FROM bsc_tokens
      `);

      const stats = result.rows[0];
      
      return {
        totalTokens: parseInt(stats.totaltokens) || 0,
        totalVolume: stats.totalvolume || '0',
        activeTraders: parseInt(stats.activetraders) || 0,
        totalLaunches: parseInt(stats.totaltokens) || 0,
        successfulLaunches: parseInt(stats.successfullaunches) || 0,
        averageRaise: stats.averageraise || '0'
      };
    } catch (error) {
      console.error('Error getting BSC stats:', error);
      return {
        totalTokens: 0,
        totalVolume: '0',
        activeTraders: 0,
        totalLaunches: 0,
        successfulLaunches: 0,
        averageRaise: '0'
      };
    }
  }

  async getTokens(options: {
    page: number;
    limit: number;
    search?: string;
    filter?: 'all' | 'active' | 'launched' | 'cancelled';
    sort?: 'newest' | 'oldest' | 'price_high' | 'price_low' | 'market_cap' | 'volume';
  }) {
    try {
      let whereClause = 'WHERE 1=1';
      const params: any[] = [];
      let paramIndex = 1;

      // Apply search filter
      if (options.search) {
        whereClause += ` AND (name ILIKE $${paramIndex} OR symbol ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`;
        params.push(`%${options.search}%`);
        paramIndex++;
      }

      // Apply status filter
      if (options.filter && options.filter !== 'all') {
        switch (options.filter) {
          case 'active':
            whereClause += ` AND launched = false AND cancelled = false AND deadline > ${Date.now() / 1000}`;
            break;
          case 'launched':
            whereClause += ` AND launched = true`;
            break;
          case 'cancelled':
            whereClause += ` AND cancelled = true`;
            break;
        }
      }

      // Apply sorting
      let orderClause = 'ORDER BY created_at DESC';
      switch (options.sort) {
        case 'newest':
          orderClause = 'ORDER BY created_at DESC';
          break;
        case 'oldest':
          orderClause = 'ORDER BY created_at ASC';
          break;
        case 'price_high':
          orderClause = 'ORDER BY CAST(current_price AS DECIMAL) DESC NULLS LAST';
          break;
        case 'price_low':
          orderClause = 'ORDER BY CAST(current_price AS DECIMAL) ASC NULLS LAST';
          break;
        case 'market_cap':
          orderClause = 'ORDER BY CAST(market_cap AS DECIMAL) DESC NULLS LAST';
          break;
        case 'volume':
          orderClause = 'ORDER BY CAST(volume_24h AS DECIMAL) DESC NULLS LAST';
          break;
      }

      const offset = (options.page - 1) * options.limit;
      params.push(options.limit, offset);

      const query = `
        SELECT * FROM bsc_tokens 
        ${whereClause} 
        ${orderClause} 
        LIMIT $${paramIndex} OFFSET $${paramIndex + 1}
      `;

      const result = await this.databaseService.query(query, params);
      
      // Get total count
      const countQuery = `SELECT COUNT(*) FROM bsc_tokens ${whereClause}`;
      const countResult = await this.databaseService.query(countQuery, params.slice(0, -2));
      const total = parseInt(countResult.rows[0].count);

      const tokens = result.rows.map(row => this.mapRowToToken(row));

      return {
        tokens,
        pagination: {
          page: options.page,
          limit: options.limit,
          total,
          totalPages: Math.ceil(total / options.limit)
        }
      };
    } catch (error) {
      console.error('Error getting BSC tokens:', error);
      return {
        tokens: [],
        pagination: {
          page: options.page,
          limit: options.limit,
          total: 0,
          totalPages: 0
        }
      };
    }
  }

  async getToken(id: string) {
    try {
      const result = await this.databaseService.query(
        'SELECT * FROM bsc_tokens WHERE id = $1',
        [id]
      );

      if (result.rows.length === 0) {
        return null;
      }

      return this.mapRowToToken(result.rows[0]);
    } catch (error) {
      console.error('Error getting BSC token:', error);
      return null;
    }
  }

  async getTokenByLaunchId(launchId: number) {
    try {
      const result = await this.databaseService.query(
        'SELECT * FROM bsc_tokens WHERE launch_id = $1',
        [launchId]
      );

      if (result.rows.length === 0) {
        return null;
      }

      return this.mapRowToToken(result.rows[0]);
    } catch (error) {
      console.error('Error getting BSC token by launch ID:', error);
      return null;
    }
  }

  /**
   * 创建代币发射（对应合约的createTokenLaunch方法）
   */
  async createTokenLaunch(createTokenDto: CreateBSCTokenDto) {
    try {
      // 1. 验证输入
      if (!createTokenDto.creatorPrivateKey) {
        throw new BadRequestException('Creator private key is required');
      }

      // 2. 从私钥得到钱包地址
      const wallet = this.contractHelper.getWallet(createTokenDto.creatorPrivateKey);
      const creatorAddress = wallet.address;

      // 3. 准备合约调用参数
      const targetAmountWei = BSCContractHelper.parseBNB(createTokenDto.targetAmount.toString());
      const creationFeeWei = ethers.parseEther('0.01'); // 0.01 BNB 创建费用

      // 4. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(createTokenDto.creatorPrivateKey);

      this.logger.log(`Creating token launch: ${createTokenDto.name} (${createTokenDto.symbol})`);

      // 5. 调用合约的createTokenLaunch方法
      const tx = await (contract as any).createTokenLaunch(
        createTokenDto.name,
        createTokenDto.symbol,
        createTokenDto.description,
        createTokenDto.website || '',
        createTokenDto.telegram || '',
        createTokenDto.twitter || '',
        targetAmountWei,
        { value: creationFeeWei }
      ) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 6. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 7. 从事件中获取launchId
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'TokenLaunchCreated';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find TokenLaunchCreated event');
      }

      const parsedEvent = contract.interface.parseLog(event);
      const launchId = parsedEvent.args.launchId.toString();
      const tokenAddress = parsedEvent.args.tokenAddress;

      this.logger.log(`Token launch created with ID: ${launchId}, Token: ${tokenAddress}`);

      // 8. 从合约获取详细信息
      const readOnlyContract = this.contractHelper.getReadOnlyContract();
      const launchInfo = await (readOnlyContract as any).getLaunchInfo(launchId);

      // 9. 保存到数据库
      const tokenId = `bsc_new_${launchId}_${Date.now()}`; // 完全避免冲突
      const query = `
        INSERT INTO bsc_tokens (
          id, launch_id, token_address, creator, name, symbol, description,
          website, telegram, twitter, target_amount, raised_amount, token_price,
          created_at, deadline, launched, cancelled, current_price, tokens_sold, total_supply_for_sale
        ) VALUES (
          $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20
        ) RETURNING *
      `;

      const values = [
        tokenId,
        parseInt(launchId),
        tokenAddress,
        creatorAddress,
        createTokenDto.name,
        createTokenDto.symbol,
        createTokenDto.description,
        createTokenDto.website || null,
        createTokenDto.telegram || null,
        createTokenDto.twitter || null,
        createTokenDto.targetAmount.toString(),
        BSCContractHelper.formatBNB(launchInfo.raisedAmount.toString()),
        BSCContractHelper.formatBNB(launchInfo.currentPrice.toString()), // token_price
        Math.floor(Date.now() / 1000),
        parseInt(launchInfo.deadline.toString()),
        launchInfo.launched,
        launchInfo.cancelled,
        BSCContractHelper.formatBNB(launchInfo.currentPrice.toString()),
        BSCContractHelper.formatTokens(launchInfo.tokensSold.toString()),
        BSCContractHelper.formatTokens(launchInfo.totalSupplyForSale.toString())
      ];

      const result = await this.databaseService.query(query, values);
      const newToken = this.mapRowToToken(result.rows[0]);

      this.logger.log(`Token saved to database: ${tokenId}`);

      return {
        success: true,
        message: 'Token launch created successfully',
        data: {
          ...newToken,
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error creating BSC token launch:', error);
      throw error;
    }
  }

  async getBondingCurveInfo(tokenId: string) {
    try {
      const token = await this.getToken(tokenId);
      if (!token) {
        throw new Error('Token not found');
      }

      return {
        basePrice: '0.0001', // 0.0001 BNB
        priceIncrement: '0.00001', // 0.00001 BNB per token
        tokensForCurve: '800000000', // 800M tokens
        tokensForLiquidity: '200000000', // 200M tokens
        currentSupply: token.tokensSold,
        currentPrice: token.currentPrice
      };
    } catch (error) {
      console.error('Error getting bonding curve info:', error);
      throw error;
    }
  }

  async getUserTokens(address: string) {
    try {
      const result = await this.databaseService.query(
        'SELECT * FROM bsc_tokens WHERE creator = $1 ORDER BY created_at DESC',
        [address]
      );

      return result.rows.map(row => this.mapRowToToken(row));
    } catch (error) {
      console.error('Error getting user BSC tokens:', error);
      return [];
    }
  }

  async getUserContributions(address: string) {
    try {
      const result = await this.databaseService.query(`
        SELECT c.*, t.name, t.symbol, t.image_url 
        FROM bsc_contributions c
        LEFT JOIN bsc_tokens t ON c.launch_id = t.launch_id
        WHERE c.contributor = $1 
        ORDER BY c.timestamp DESC
      `, [address]);

      return result.rows.map(row => ({
        id: row.id,
        launchId: row.launch_id,
        contributor: row.contributor,
        amount: row.amount,
        tokensReceived: row.tokens_received,
        bnbReceived: row.bnb_received,
        timestamp: row.timestamp,
        txHash: row.tx_hash,
        tradeType: row.trade_type,
        tokenName: row.name,
        tokenSymbol: row.symbol,
        tokenImageUrl: row.image_url
      }));
    } catch (error) {
      console.error('Error getting user contributions:', error);
      return [];
    }
  }

  async uploadImage(file: Express.Multer.File) {
    try {
      // Create uploads directory if it doesn't exist
      const uploadsDir = path.join(process.cwd(), 'uploads', 'bsc');
      if (!fs.existsSync(uploadsDir)) {
        fs.mkdirSync(uploadsDir, { recursive: true });
      }

      // Generate unique filename
      const fileExtension = path.extname(file.originalname);
      const filename = `bsc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}${fileExtension}`;
      const filePath = path.join(uploadsDir, filename);

      // Write file
      fs.writeFileSync(filePath, file.buffer);

      // Return URL
      const baseUrl = process.env.BASE_URL || 'http://localhost:3001';
      const imageUrl = `${baseUrl}/uploads/bsc/${filename}`;

      return { url: imageUrl };
    } catch (error) {
      console.error('Error uploading BSC image:', error);
      throw error;
    }
  }

  async getTokenChart(tokenId: string, timeframe: '1h' | '24h' | '7d' | '30d') {
    try {
      // TODO: Implement actual price history from blockchain or price feeds
      // For now, return mock data
      const token = await this.getToken(tokenId);
      if (!token) {
        throw new Error('Token not found');
      }

      const prices = this.generateMockPriceData(token, timeframe);
      
      return {
        prices,
        timeframe
      };
    } catch (error) {
      console.error('Error getting token chart data:', error);
      return {
        prices: [],
        timeframe
      };
    }
  }

  async getTokenHolders(tokenId: string) {
    try {
      // TODO: Implement token holder tracking
      return [];
    } catch (error) {
      console.error('Error getting token holders:', error);
      return [];
    }
  }

  async getTokenTransactions(tokenId: string, limit: number) {
    try {
      const result = await this.databaseService.query(`
        SELECT * FROM bsc_contributions 
        WHERE launch_id = (SELECT launch_id FROM bsc_tokens WHERE id = $1)
        ORDER BY timestamp DESC
        LIMIT $2
      `, [tokenId, limit]);

      return result.rows.map(row => ({
        id: row.id,
        type: row.trade_type,
        contributor: row.contributor,
        amount: row.amount,
        tokensReceived: row.tokens_received,
        bnbReceived: row.bnb_received,
        timestamp: row.timestamp,
        txHash: row.tx_hash
      }));
    } catch (error) {
      console.error('Error getting token transactions:', error);
      return [];
    }
  }

  private mapRowToToken(row: any): BSCToken {
    return {
      id: row.id,
      launchId: row.launch_id,
      tokenAddress: row.token_address,
      creator: row.creator,
      name: row.name,
      symbol: row.symbol,
      description: row.description,
      website: row.website,
      telegram: row.telegram,
      twitter: row.twitter,
      imageUrl: row.image_url,
      targetAmount: row.target_amount,
      raisedAmount: row.raised_amount,
      createdAt: row.created_at,
      deadline: row.deadline,
      launched: row.launched,
      cancelled: row.cancelled,
      currentPrice: row.current_price,
      tokensSold: row.tokens_sold,
      totalSupplyForSale: row.total_supply_for_sale,
      priceChange24h: row.price_change_24h ? parseFloat(row.price_change_24h.toString()) : null,
      volume24h: row.volume_24h,
      marketCap: row.market_cap,
      holders: row.holders
    };
  }

  private calculateTokensForBNB(currentTokensSold: number, bnbAmount: number): number {
    // Simplified calculation for linear bonding curve
    const currentPrice = this.calculatePrice(currentTokensSold);
    const avgPrice = currentPrice + (0.00001 / 2); // Approximate average price
    return bnbAmount / avgPrice;
  }

  private calculateBNBForTokens(currentTokensSold: number, tokenAmount: number): number {
    // Simplified calculation for linear bonding curve
    const currentPrice = this.calculatePrice(currentTokensSold);
    const avgPrice = currentPrice - (0.00001 / 2); // Approximate average price
    return tokenAmount * Math.max(avgPrice, 0.0001); // Minimum price floor
  }

  private generateMockPriceData(token: BSCToken, timeframe: string) {
    const now = Date.now();
    const data = [];
    const points = timeframe === '1h' ? 60 : timeframe === '24h' ? 24 : timeframe === '7d' ? 7 : 30;
    const interval = timeframe === '1h' ? 60000 : timeframe === '24h' ? 3600000 : 24 * 3600000;
    
    const basePrice = parseFloat(token.currentPrice);
    let currentPrice = basePrice;
    
    for (let i = points; i >= 0; i--) {
      const timestamp = now - (i * interval);
      
      // Simulate price movement
      const change = (Math.random() - 0.5) * 0.1;
      currentPrice = Math.max(basePrice * 0.5, currentPrice * (1 + change));
      
      const volume = Math.random() * 10;
      const tokensSold = parseFloat(token.tokensSold) * Math.random();
      
      data.push({
        timestamp,
        price: currentPrice,
        volume,
        tokensSold
      });
    }
    
    return data;
  }

  // 新增方法以匹配控制器期望

    /**
   * 购买代币（对应合约的buyTokens方法）
   */
  async buyTokens(buyTokenDto: BuyBSCTokenDto) {
    try {
      // 1. 验证输入
      if (!buyTokenDto.buyerPrivateKey) {
        throw new BadRequestException('Buyer private key is required');
      }

      // 2. 获取钱包和地址
      const wallet = this.contractHelper.getWallet(buyTokenDto.buyerPrivateKey);
      const buyerAddress = wallet.address;

      // 3. 检查token是否存在
      const token = await this.getTokenByLaunchId(buyTokenDto.launchId);
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // 4. 验证购买条件
      if (token.launched || token.cancelled) {
        throw new BadRequestException('Token launch is not active');
      }

      const now = Math.floor(Date.now() / 1000);
      if (now > token.deadline) {
        throw new BadRequestException('Token launch has expired');
      }

      // 5. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(buyTokenDto.buyerPrivateKey);

      // 6. 计算购买金额
      const bnbAmountWei = BSCContractHelper.parseBNB(buyTokenDto.bnbAmount.toString());

      this.logger.log(`Buying tokens for launch ${buyTokenDto.launchId}, amount: ${buyTokenDto.bnbAmount} BNB`);

      // 7. 调用合约的buyTokens方法
      const tx = await (contract as any).buyTokens(
        buyTokenDto.launchId,
        { value: bnbAmountWei }
      ) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 8. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 9. 从事件中获取购买信息
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'TokenPurchase';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find TokenPurchase event');
      }

      const parsedEvent = contract.interface.parseLog(event);
      const tokenAmount = parsedEvent.args.tokensReceived;
      const totalPaid = parsedEvent.args.bnbAmount;

      this.logger.log(`Tokens purchased: ${BSCContractHelper.formatTokens(tokenAmount.toString())} tokens for ${BSCContractHelper.formatBNB(totalPaid.toString())} BNB`);

      // 10. 更新数据库中的token信息
      const readOnlyContract = this.contractHelper.getReadOnlyContract();
      const launchInfo = await (readOnlyContract as any).getLaunchInfo(buyTokenDto.launchId);

      await this.databaseService.query(`
        UPDATE bsc_tokens 
        SET raised_amount = $1,
            tokens_sold = $2,
            current_price = $3,
            launched = $4
        WHERE launch_id = $5
      `, [
        BSCContractHelper.formatBNB(launchInfo.raisedAmount.toString()),
        BSCContractHelper.formatTokens(launchInfo.tokensSold.toString()),
        BSCContractHelper.formatBNB(launchInfo.currentPrice.toString()),
        launchInfo.launched,
        buyTokenDto.launchId
      ]);

      // 11. 记录交易
      await this.databaseService.query(`
        INSERT INTO bsc_contributions (
          id, launch_id, contributor, amount, tokens_received, timestamp, tx_hash, trade_type
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
      `, [
        `trade_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        buyTokenDto.launchId,
        buyerAddress,
        BSCContractHelper.formatBNB(totalPaid.toString()),
        BSCContractHelper.formatTokens(tokenAmount.toString()),
        Math.floor(Date.now() / 1000),
        receipt.hash,
        'buy'
      ]);

      return {
        success: true,
        message: 'Tokens purchased successfully',
        data: {
          launchId: buyTokenDto.launchId,
          buyerAddress,
          bnbAmount: BSCContractHelper.formatBNB(totalPaid.toString()),
          tokensReceived: BSCContractHelper.formatTokens(tokenAmount.toString()),
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error buying BSC tokens:', error);
      throw error;
    }
  }

  /**
   * 出售代币（对应合约的sellTokens方法）
   */
  async sellTokens(sellTokenDto: SellBSCTokenDto) {
    try {
      // 1. 验证输入
      if (!sellTokenDto.sellerPrivateKey) {
        throw new BadRequestException('Seller private key is required');
      }

      // 2. 获取钱包和地址
      const wallet = this.contractHelper.getWallet(sellTokenDto.sellerPrivateKey);
      const sellerAddress = wallet.address;

      // 3. 检查token是否存在
      const token = await this.getTokenByLaunchId(sellTokenDto.launchId);
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // 4. 验证出售条件
      if (token.launched || token.cancelled) {
        throw new BadRequestException('Token launch is not active');
      }

      const now = Math.floor(Date.now() / 1000);
      if (now > token.deadline) {
        throw new BadRequestException('Token launch has expired');
      }

      // 5. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(sellTokenDto.sellerPrivateKey);

      // 6. 计算要出售的代币数量
      const tokenAmountWei = BSCContractHelper.parseTokens(sellTokenDto.tokenAmount.toString());

      // 7. 获取代币合约实例并检查/设置授权
      const tokenContract = new ethers.Contract(
        token.tokenAddress,
        [
          'function balanceOf(address owner) view returns (uint256)',
          'function allowance(address owner, address spender) view returns (uint256)',
          'function approve(address spender, uint256 amount) returns (bool)'
        ],
        this.contractHelper.getWallet(sellTokenDto.sellerPrivateKey)
      );

      // 检查用户的代币余额
      const userBalance = await tokenContract.balanceOf(sellerAddress);
      if (userBalance < tokenAmountWei) {
        throw new BadRequestException('Insufficient token balance');
      }

      // 检查当前授权额度
      const currentAllowance = await tokenContract.allowance(sellerAddress, this.LAUNCHPAD_ADDRESS);
      
      // 如果授权不足，先进行授权
      if (currentAllowance < tokenAmountWei) {
        this.logger.log(`Approving token spending: ${BSCContractHelper.formatTokens(tokenAmountWei.toString())} tokens`);
        
        const approveTx = await tokenContract.approve(
          this.LAUNCHPAD_ADDRESS,
          tokenAmountWei
        ) as ethers.ContractTransactionResponse;
        
        await approveTx.wait();
        this.logger.log(`Token approval confirmed: ${approveTx.hash}`);
      }

      this.logger.log(`Selling tokens for launch ${sellTokenDto.launchId}, amount: ${sellTokenDto.tokenAmount} tokens`);

      // 8. 调用合约的sellTokens方法
      const tx = await (contract as any).sellTokens(
        sellTokenDto.launchId,
        tokenAmountWei
      ) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 8. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 9. 从事件中获取出售信息
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'TokenSale';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find TokenSale event');
      }

      const parsedEvent = contract.interface.parseLog(event);
      const tokenAmount = parsedEvent.args.tokensAmount;
      const bnbReceived = parsedEvent.args.bnbReceived;

      this.logger.log(`Tokens sold: ${BSCContractHelper.formatTokens(tokenAmount.toString())} tokens for ${BSCContractHelper.formatBNB(bnbReceived.toString())} BNB`);

      // 10. 更新数据库中的token信息
      const readOnlyContract = this.contractHelper.getReadOnlyContract();
      const launchInfo = await (readOnlyContract as any).getLaunchInfo(sellTokenDto.launchId);

      await this.databaseService.query(`
        UPDATE bsc_tokens 
        SET raised_amount = $1,
            tokens_sold = $2,
            current_price = $3,
            launched = $4
        WHERE launch_id = $5
      `, [
        BSCContractHelper.formatBNB(launchInfo.raisedAmount.toString()),
        BSCContractHelper.formatTokens(launchInfo.tokensSold.toString()),
        BSCContractHelper.formatBNB(launchInfo.currentPrice.toString()),
        launchInfo.launched,
        sellTokenDto.launchId
      ]);

      // 11. 记录交易
      await this.databaseService.query(`
        INSERT INTO bsc_contributions (
          id, launch_id, contributor, amount, tokens_sold, trade_type, timestamp, tx_hash
        ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
      `, [
        `trade_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        sellTokenDto.launchId,
        sellerAddress,
        BSCContractHelper.formatBNB(bnbReceived.toString()), // amount (BNB received for sells)
        BSCContractHelper.formatTokens(tokenAmount.toString()),
        'sell',
        Math.floor(Date.now() / 1000),
        receipt.hash
      ]);

      return {
        success: true,
        message: 'Tokens sold successfully',
        data: {
          launchId: sellTokenDto.launchId,
          sellerAddress,
          tokenAmount: BSCContractHelper.formatTokens(tokenAmount.toString()),
          bnbReceived: BSCContractHelper.formatBNB(bnbReceived.toString()),
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error selling BSC tokens:', error);
      throw error;
    }
  }

  /**
   * 获取交易预览
   */
  async getTradePreview(launchId: number, bnbAmount?: number, tokenAmount?: number) {
    try {
      const readOnlyContract = this.contractHelper.getReadOnlyContract();

      if (bnbAmount) {
        // 计算购买预览
        const bnbAmountWei = BSCContractHelper.parseBNB(bnbAmount.toString());
        const preview = await (readOnlyContract as any).previewBuy(launchId, bnbAmountWei);
        
        return {
          type: 'buy',
          bnbAmount: bnbAmount.toString(),
          tokensReceived: BSCContractHelper.formatTokens(preview.tokensOut.toString()),
          newPrice: BSCContractHelper.formatBNB(preview.newPrice.toString()),
          totalCost: BSCContractHelper.formatBNB(preview.totalCost.toString())
        };
      }

      if (tokenAmount) {
        // 计算出售预览
        const tokenAmountWei = BSCContractHelper.parseTokens(tokenAmount.toString());
        const preview = await (readOnlyContract as any).previewSell(launchId, tokenAmountWei);
        
        return {
          type: 'sell',
          tokenAmount: tokenAmount.toString(),
          bnbReceived: BSCContractHelper.formatBNB(preview.bnbOut.toString()),
          newPrice: BSCContractHelper.formatBNB(preview.newPrice.toString())
        };
      }

      throw new BadRequestException('Either bnbAmount or tokenAmount must be provided');
    } catch (error) {
      this.logger.error('Error getting trade preview:', error);
      throw error;
    }
  }

  /**
   * 毕业代币到PancakeSwap（对应合约的manualGraduateToken方法）
   */
  async graduateToken(graduateDto: GraduateBSCTokenDto) {
    try {
      // 1. 验证输入
      if (!graduateDto.creatorPrivateKey) {
        throw new BadRequestException('Creator private key is required');
      }

      // 2. 获取钱包和地址
      const wallet = this.contractHelper.getWallet(graduateDto.creatorPrivateKey);
      const creatorAddress = wallet.address;

      // 3. 获取token信息
      const token = await this.getToken(graduateDto.launchId.toString());
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // 4. 验证权限
      if (token.creator.toLowerCase() !== creatorAddress.toLowerCase()) {
        throw new BadRequestException('Only creator can graduate token');
      }

      // 5. 验证毕业条件
      if (token.launched) {
        throw new BadRequestException('Token already graduated');
      }

      if (token.cancelled) {
        throw new BadRequestException('Cannot graduate cancelled token');
      }

      // 6. 检查是否满足毕业条件
      const readOnlyContract = this.contractHelper.getReadOnlyContract();
      const canGraduate = await (readOnlyContract as any).canGraduate(graduateDto.launchId);
      
      if (!canGraduate) {
        throw new BadRequestException('Token does not meet graduation requirements');
      }

      // 7. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(graduateDto.creatorPrivateKey);

      this.logger.log(`Graduating token launch ${graduateDto.launchId}`);

      // 8. 调用合约的manualGraduateToken方法
      const tx = await (contract as any).manualGraduateToken(graduateDto.launchId) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 9. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 10. 从事件中获取毕业信息
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'TokenGraduated';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find TokenGraduated event');
      }

      const parsedEvent = contract.interface.parseLog(event);
      const tokenAddress = parsedEvent.args.tokenAddress;
      const liquidityBNB = parsedEvent.args.liquidityBNB;
      const liquidityTokens = parsedEvent.args.liquidityTokens;

      this.logger.log(`Token graduated: ${tokenAddress}, Liquidity: ${BSCContractHelper.formatBNB(liquidityBNB.toString())} BNB`);

      // 11. 更新数据库状态
      await this.databaseService.query(`
        UPDATE bsc_tokens 
        SET launched = true
        WHERE launch_id = $1
      `, [graduateDto.launchId]);

      return {
        success: true,
        message: 'Token graduated successfully to PancakeSwap',
        data: {
          launchId: graduateDto.launchId,
          tokenAddress: tokenAddress,
          liquidityBNB: BSCContractHelper.formatBNB(liquidityBNB.toString()),
          liquidityTokens: BSCContractHelper.formatTokens(liquidityTokens.toString()),
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error graduating BSC token:', error);
      throw error;
    }
  }

  /**
   * 取消发射（对应合约的cancelLaunch方法）
   */
  async cancelLaunch(cancelDto: CancelBSCLaunchDto) {
    try {
      // 1. 验证输入
      if (!cancelDto.creatorPrivateKey) {
        throw new BadRequestException('Creator private key is required');
      }

      // 2. 获取钱包和地址
      const wallet = this.contractHelper.getWallet(cancelDto.creatorPrivateKey);
      const creatorAddress = wallet.address;

      // 3. 获取token信息
      const token = await this.getToken(cancelDto.launchId.toString());
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // 4. 验证权限
      if (token.creator.toLowerCase() !== creatorAddress.toLowerCase()) {
        throw new BadRequestException('Only creator can cancel launch');
      }

      // 5. 验证取消条件
      if (token.launched) {
        throw new BadRequestException('Cannot cancel launched token');
      }

      if (token.cancelled) {
        throw new BadRequestException('Token already cancelled');
      }

      // 6. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(cancelDto.creatorPrivateKey);

      this.logger.log(`Cancelling token launch ${cancelDto.launchId}`);

      // 7. 调用合约的cancelLaunch方法
      const tx = await (contract as any).cancelLaunch(cancelDto.launchId) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 8. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 9. 从事件中获取取消信息
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'LaunchCancelled';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find LaunchCancelled event');
      }

      this.logger.log(`Launch cancelled: ${cancelDto.launchId}`);

      // 10. 更新数据库状态
      await this.databaseService.query(`
        UPDATE bsc_tokens 
        SET cancelled = true
        WHERE launch_id = $1
      `, [cancelDto.launchId]);

      return {
        success: true,
        message: 'Launch cancelled successfully',
        data: {
          launchId: cancelDto.launchId,
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error cancelling BSC launch:', error);
      throw error;
    }
  }

  /**
   * 申请退款（对应合约的claimRefund方法）
   */
  async claimRefund(refundDto: ClaimRefundDto) {
    try {
      // 1. 验证输入
      if (!refundDto.userPrivateKey) {
        throw new BadRequestException('User private key is required');
      }

      // 2. 获取钱包和地址
      const wallet = this.contractHelper.getWallet(refundDto.userPrivateKey);
      const userAddress = wallet.address;

      // 3. 获取token信息
      const token = await this.getToken(refundDto.launchId.toString());
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // 4. 检查是否可以退款
      const readOnlyContract = this.contractHelper.getReadOnlyContract();
      const canClaim = await (readOnlyContract as any).canClaimRefund(refundDto.launchId, userAddress);
      
      if (!canClaim) {
        throw new BadRequestException('No refund available for this user');
      }

      // 5. 获取合约实例
      const contract = this.contractHelper.getContractWithSigner(refundDto.userPrivateKey);

      this.logger.log(`Claiming refund for launch ${refundDto.launchId}, user: ${userAddress}`);

      // 6. 调用合约的claimRefund方法
      const tx = await (contract as any).claimRefund(refundDto.launchId) as ethers.ContractTransactionResponse;

      this.logger.log(`Transaction sent: ${tx.hash}`);
      
      // 7. 等待交易确认
      const receipt = await tx.wait();
      this.logger.log(`Transaction confirmed: ${receipt.hash}`);

      // 8. 从事件中获取退款信息
      const event = receipt.logs.find(log => {
        try {
          const parsed = contract.interface.parseLog(log);
          return parsed.name === 'RefundClaimed';
        } catch {
          return false;
        }
      });

      if (!event) {
        throw new Error('Failed to find RefundClaimed event');
      }

      const parsedEvent = contract.interface.parseLog(event);
      const refundAmount = parsedEvent.args.refundAmount;

      this.logger.log(`Refund claimed: ${BSCContractHelper.formatBNB(refundAmount.toString())} BNB`);

      // 9. 更新数据库 - 清除用户的贡献记录
      await this.databaseService.query(`
        DELETE FROM bsc_contributions 
        WHERE launch_id = $1 AND contributor = $2
      `, [refundDto.launchId, userAddress]);

      return {
        success: true,
        message: 'Refund claimed successfully',
        data: {
          launchId: refundDto.launchId,
          userAddress,
          refundAmount: BSCContractHelper.formatBNB(refundAmount.toString()),
          transactionHash: receipt.hash,
          gasUsed: receipt.gasUsed.toString()
        }
      };
    } catch (error) {
      this.logger.error('Error claiming BSC refund:', error);
      throw error;
    }
  }

  /**
   * 获取用户贡献
   */
  async getUserContribution(launchId: number, userAddress: string) {
    try {
      const query = `
        SELECT 
          COALESCE(SUM(CASE WHEN trade_type = 'buy' THEN CAST(amount AS DECIMAL) ELSE 0 END), 0) as total_contributed,
          COALESCE(SUM(CASE WHEN trade_type = 'buy' THEN CAST(tokens_received AS DECIMAL) ELSE -CAST(tokens_sold AS DECIMAL) END), 0) as token_balance
        FROM bsc_contributions 
        WHERE launch_id = $1 AND contributor = $2
      `;
      
      const result = await this.databaseService.query(query, [launchId, userAddress]);
      
      if (result.rows.length > 0) {
        const row = result.rows[0];
        return {
          bnbContribution: row.total_contributed?.toString() || '0',
          tokenBalance: row.token_balance?.toString() || '0'
        };
      }
      
      return {
        bnbContribution: '0',
        tokenBalance: '0'
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取贡献者列表
   */
  async getContributors(launchId: number) {
    try {
      const query = `
        SELECT DISTINCT contributor
        FROM bsc_contributions 
        WHERE launch_id = $1
        ORDER BY contributor
      `;
      
      const result = await this.databaseService.query(query, [launchId]);
      return result.rows.map(row => row.contributor);
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取代币社交媒体信息
   */
  async getTokenSocialInfo(launchId: number) {
    try {
      const query = `
        SELECT website, telegram, twitter
        FROM bsc_tokens 
        WHERE launch_id = $1
      `;
      
      const result = await this.databaseService.query(query, [launchId]);
      
      if (result.rows.length === 0) {
        throw new NotFoundException('Token not found');
      }
      
      const row = result.rows[0];
      return {
        website: row.website,
        telegram: row.telegram,
        twitter: row.twitter
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取购买预览
   */
  async getBuyPreview(launchId: string, bnbAmount: string) {
    try {
      const token = await this.getTokenByLaunchId(parseInt(launchId));
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      const bnbAmountNum = parseFloat(bnbAmount);
      const tokensReceived = this.calculateTokensForBNB(parseFloat(token.tokensSold), bnbAmountNum);
      const newTokensSold = parseFloat(token.tokensSold) + tokensReceived;
      const newPrice = this.calculatePrice(newTokensSold);
      
      return {
        tokensReceived: tokensReceived.toString(),
        newPrice: newPrice.toString(),
        priceImpact: this.calculatePriceImpact(parseFloat(token.currentPrice), newPrice)
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取出售预览
   */
  async getSellPreview(launchId: string, tokenAmount: string) {
    try {
      const token = await this.getTokenByLaunchId(parseInt(launchId));
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      const tokenAmountNum = parseFloat(tokenAmount);
      const bnbReceived = this.calculateBNBForTokens(parseFloat(token.tokensSold), tokenAmountNum);
      const newTokensSold = Math.max(0, parseFloat(token.tokensSold) - tokenAmountNum);
      const newPrice = this.calculatePrice(newTokensSold);
      
      return {
        bnbReceived: bnbReceived.toString(),
        newPrice: newPrice.toString(),
        priceImpact: this.calculatePriceImpact(parseFloat(token.currentPrice), newPrice)
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 计算联合曲线价格
   */
  private calculatePrice(tokensSold: number): number {
    const CURVE_BASE_PRICE = 0.0001; // 0.0001 BNB
    const CURVE_PRICE_INCREMENT = 0.00001; // 0.00001 BNB per token
    
    return CURVE_BASE_PRICE + (tokensSold * CURVE_PRICE_INCREMENT / 1e18);
  }

  /**
   * 计算价格影响
   */
  private calculatePriceImpact(oldPrice: number, newPrice: number): number {
    if (oldPrice === 0) return 0;
    return ((newPrice - oldPrice) / oldPrice) * 100;
  }

  /**
   * 从合约同步代币信息
   */
  async syncTokenFromContract(launchId: string): Promise<any> {
    try {
      // TODO: 实现从合约读取数据并更新数据库
      return {
        message: 'Contract sync functionality not yet implemented',
        launchId
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取价格历史
   */
  async getPriceHistory(launchId: string, timeframe: string = '24h'): Promise<any> {
    try {
      const token = await this.getToken(launchId);
      if (!token) {
        throw new NotFoundException('Token not found');
      }

      // TODO: 实现真实的价格历史数据
      // 目前返回模拟数据
      const now = Date.now();
      const data = [];
      const points = timeframe === '1h' ? 60 : timeframe === '24h' ? 24 : timeframe === '7d' ? 7 : 30;
      const interval = timeframe === '1h' ? 60000 : timeframe === '24h' ? 3600000 : 24 * 3600000;
      
      const basePrice = parseFloat(token.currentPrice);
      
      for (let i = points; i >= 0; i--) {
        const timestamp = now - (i * interval);
        const variation = (Math.random() - 0.5) * 0.1; // ±10% variation
        const price = basePrice * (1 + variation);
        
        data.push({
          timestamp,
          price: price.toFixed(8),
          volume: (Math.random() * 1000).toFixed(2)
        });
      }

      return {
        timeframe,
        data
      };
    } catch (error) {
      throw error;
    }
  }

  /**
   * 获取交易历史
   */
  async getTradeHistory(launchId: string, page: number = 1, limit: number = 20): Promise<any> {
    try {
      const offset = (page - 1) * limit;
      
      const query = `
        SELECT * FROM bsc_contributions 
        WHERE launch_id = $1 
        ORDER BY timestamp DESC
        LIMIT $2 OFFSET $3
      `;
      
      const result = await this.databaseService.query(query, [parseInt(launchId), limit, offset]);
      
      // Get total count
      const countQuery = `SELECT COUNT(*) FROM bsc_contributions WHERE launch_id = $1`;
      const countResult = await this.databaseService.query(countQuery, [parseInt(launchId)]);
      const total = parseInt(countResult.rows[0].count);
      
      const trades = result.rows.map(row => ({
        id: row.id,
        launchId: row.launch_id,
        trader: row.contributor,
        amount: row.amount,
        tokensReceived: row.tokens_received,
        bnbReceived: row.bnb_received,
        timestamp: row.timestamp,
        txHash: row.tx_hash,
        tradeType: row.trade_type
      }));

      return {
        trades,
        pagination: {
          page,
          limit,
          total,
          totalPages: Math.ceil(total / limit)
        }
      };
    } catch (error) {
      throw error;
    }
  }
}